House Price - Data Prep

1 Objetivos

  • Número de variáveis: 81
  • Tipo de variáveis
      • Inteiras ou discretas:
      • Numéricas ou double
      • Categóricas
      • Qualitativas
    • Qualidade dos dados
      • Quantidade de NA’s por variável
  • Criação de novas variáveis, se precisar
  • Transformação das variáveis, se precisar

2 Conjunto de Dados

O dataprep será realizado considerando que os dados de treinamento e de teste foram amostrados de tal forma que as proporções de valores assumidos por cada variável estão equilibradas nas duas amostras.

2.1 Dados de treinamento

# Read table 
df.train <- data.table::fread('../dados/train.csv', 
                              sep=",", 
                              showProgress = FALSE) %>% 
            data.frame(stringsAsFactors = F)
df.train

3 Conhecendo as caracteristicas dos dados

str(df.train)
## 'data.frame':    1460 obs. of  81 variables:
##  $ Id           : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ MSSubClass   : int  60 20 60 70 60 50 20 60 50 190 ...
##  $ MSZoning     : chr  "RL" "RL" "RL" "RL" ...
##  $ LotFrontage  : int  65 80 68 60 84 85 75 NA 51 50 ...
##  $ LotArea      : int  8450 9600 11250 9550 14260 14115 10084 10382 6120 7420 ...
##  $ Street       : chr  "Pave" "Pave" "Pave" "Pave" ...
##  $ Alley        : chr  NA NA NA NA ...
##  $ LotShape     : chr  "Reg" "Reg" "IR1" "IR1" ...
##  $ LandContour  : chr  "Lvl" "Lvl" "Lvl" "Lvl" ...
##  $ Utilities    : chr  "AllPub" "AllPub" "AllPub" "AllPub" ...
##  $ LotConfig    : chr  "Inside" "FR2" "Inside" "Corner" ...
##  $ LandSlope    : chr  "Gtl" "Gtl" "Gtl" "Gtl" ...
##  $ Neighborhood : chr  "CollgCr" "Veenker" "CollgCr" "Crawfor" ...
##  $ Condition1   : chr  "Norm" "Feedr" "Norm" "Norm" ...
##  $ Condition2   : chr  "Norm" "Norm" "Norm" "Norm" ...
##  $ BldgType     : chr  "1Fam" "1Fam" "1Fam" "1Fam" ...
##  $ HouseStyle   : chr  "2Story" "1Story" "2Story" "2Story" ...
##  $ OverallQual  : int  7 6 7 7 8 5 8 7 7 5 ...
##  $ OverallCond  : int  5 8 5 5 5 5 5 6 5 6 ...
##  $ YearBuilt    : int  2003 1976 2001 1915 2000 1993 2004 1973 1931 1939 ...
##  $ YearRemodAdd : int  2003 1976 2002 1970 2000 1995 2005 1973 1950 1950 ...
##  $ RoofStyle    : chr  "Gable" "Gable" "Gable" "Gable" ...
##  $ RoofMatl     : chr  "CompShg" "CompShg" "CompShg" "CompShg" ...
##  $ Exterior1st  : chr  "VinylSd" "MetalSd" "VinylSd" "Wd Sdng" ...
##  $ Exterior2nd  : chr  "VinylSd" "MetalSd" "VinylSd" "Wd Shng" ...
##  $ MasVnrType   : chr  "BrkFace" "None" "BrkFace" "None" ...
##  $ MasVnrArea   : int  196 0 162 0 350 0 186 240 0 0 ...
##  $ ExterQual    : chr  "Gd" "TA" "Gd" "TA" ...
##  $ ExterCond    : chr  "TA" "TA" "TA" "TA" ...
##  $ Foundation   : chr  "PConc" "CBlock" "PConc" "BrkTil" ...
##  $ BsmtQual     : chr  "Gd" "Gd" "Gd" "TA" ...
##  $ BsmtCond     : chr  "TA" "TA" "TA" "Gd" ...
##  $ BsmtExposure : chr  "No" "Gd" "Mn" "No" ...
##  $ BsmtFinType1 : chr  "GLQ" "ALQ" "GLQ" "ALQ" ...
##  $ BsmtFinSF1   : int  706 978 486 216 655 732 1369 859 0 851 ...
##  $ BsmtFinType2 : chr  "Unf" "Unf" "Unf" "Unf" ...
##  $ BsmtFinSF2   : int  0 0 0 0 0 0 0 32 0 0 ...
##  $ BsmtUnfSF    : int  150 284 434 540 490 64 317 216 952 140 ...
##  $ TotalBsmtSF  : int  856 1262 920 756 1145 796 1686 1107 952 991 ...
##  $ Heating      : chr  "GasA" "GasA" "GasA" "GasA" ...
##  $ HeatingQC    : chr  "Ex" "Ex" "Ex" "Gd" ...
##  $ CentralAir   : chr  "Y" "Y" "Y" "Y" ...
##  $ Electrical   : chr  "SBrkr" "SBrkr" "SBrkr" "SBrkr" ...
##  $ X1stFlrSF    : int  856 1262 920 961 1145 796 1694 1107 1022 1077 ...
##  $ X2ndFlrSF    : int  854 0 866 756 1053 566 0 983 752 0 ...
##  $ LowQualFinSF : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ GrLivArea    : int  1710 1262 1786 1717 2198 1362 1694 2090 1774 1077 ...
##  $ BsmtFullBath : int  1 0 1 1 1 1 1 1 0 1 ...
##  $ BsmtHalfBath : int  0 1 0 0 0 0 0 0 0 0 ...
##  $ FullBath     : int  2 2 2 1 2 1 2 2 2 1 ...
##  $ HalfBath     : int  1 0 1 0 1 1 0 1 0 0 ...
##  $ BedroomAbvGr : int  3 3 3 3 4 1 3 3 2 2 ...
##  $ KitchenAbvGr : int  1 1 1 1 1 1 1 1 2 2 ...
##  $ KitchenQual  : chr  "Gd" "TA" "Gd" "Gd" ...
##  $ TotRmsAbvGrd : int  8 6 6 7 9 5 7 7 8 5 ...
##  $ Functional   : chr  "Typ" "Typ" "Typ" "Typ" ...
##  $ Fireplaces   : int  0 1 1 1 1 0 1 2 2 2 ...
##  $ FireplaceQu  : chr  NA "TA" "TA" "Gd" ...
##  $ GarageType   : chr  "Attchd" "Attchd" "Attchd" "Detchd" ...
##  $ GarageYrBlt  : int  2003 1976 2001 1998 2000 1993 2004 1973 1931 1939 ...
##  $ GarageFinish : chr  "RFn" "RFn" "RFn" "Unf" ...
##  $ GarageCars   : int  2 2 2 3 3 2 2 2 2 1 ...
##  $ GarageArea   : int  548 460 608 642 836 480 636 484 468 205 ...
##  $ GarageQual   : chr  "TA" "TA" "TA" "TA" ...
##  $ GarageCond   : chr  "TA" "TA" "TA" "TA" ...
##  $ PavedDrive   : chr  "Y" "Y" "Y" "Y" ...
##  $ WoodDeckSF   : int  0 298 0 0 192 40 255 235 90 0 ...
##  $ OpenPorchSF  : int  61 0 42 35 84 30 57 204 0 4 ...
##  $ EnclosedPorch: int  0 0 0 272 0 0 0 228 205 0 ...
##  $ X3SsnPorch   : int  0 0 0 0 0 320 0 0 0 0 ...
##  $ ScreenPorch  : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ PoolArea     : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ PoolQC       : chr  NA NA NA NA ...
##  $ Fence        : chr  NA NA NA NA ...
##  $ MiscFeature  : chr  NA NA NA NA ...
##  $ MiscVal      : int  0 0 0 0 0 700 0 350 0 0 ...
##  $ MoSold       : int  2 5 9 2 12 10 8 11 4 1 ...
##  $ YrSold       : int  2008 2007 2008 2006 2008 2009 2007 2009 2008 2008 ...
##  $ SaleType     : chr  "WD" "WD" "WD" "WD" ...
##  $ SaleCondition: chr  "Normal" "Normal" "Normal" "Abnorml" ...
##  $ SalePrice    : int  208500 181500 223500 140000 250000 143000 307000 200000 129900 118000 ...

Nosso conjunto de dados apresenta somente dois tipos de dados, além disso a primeira vista há muitos dados faltantes ou nulos.

4 Separando o conjunto de dados pelo tipo.

tipo <- lapply(df.train,class)

4.1 Dados tipo inteiro

df.int <- df.train[,unlist(tipo) %in% "integer"]
df.int

4.2 Dados tipo string

df.str <- df.train[,unlist(tipo) %in% "character"]
df.str

4.3 Tranformando dados tipo string em categorical.

Afim de medir a influência que determinado valor de uma variável string exerce sobre a variável resposta, iremos tranformá-las em variável categórica.

df.cat <- lapply(df.str,factor) %>% data.frame()
df.cat

5 Data Profiling

5.1 Tipo inteiro: % de valores nulos

apply(is.na(df.int),2,
            function(x) round(100*sum(as.numeric(x))/length(x),2)) %>% 
            sort(decreasing = T)
##   LotFrontage   GarageYrBlt    MasVnrArea            Id    MSSubClass 
##         17.74          5.55          0.55          0.00          0.00 
##       LotArea   OverallQual   OverallCond     YearBuilt  YearRemodAdd 
##          0.00          0.00          0.00          0.00          0.00 
##    BsmtFinSF1    BsmtFinSF2     BsmtUnfSF   TotalBsmtSF     X1stFlrSF 
##          0.00          0.00          0.00          0.00          0.00 
##     X2ndFlrSF  LowQualFinSF     GrLivArea  BsmtFullBath  BsmtHalfBath 
##          0.00          0.00          0.00          0.00          0.00 
##      FullBath      HalfBath  BedroomAbvGr  KitchenAbvGr  TotRmsAbvGrd 
##          0.00          0.00          0.00          0.00          0.00 
##    Fireplaces    GarageCars    GarageArea    WoodDeckSF   OpenPorchSF 
##          0.00          0.00          0.00          0.00          0.00 
## EnclosedPorch    X3SsnPorch   ScreenPorch      PoolArea       MiscVal 
##          0.00          0.00          0.00          0.00          0.00 
##        MoSold        YrSold     SalePrice 
##          0.00          0.00          0.00

De forma geral podemos concluir que não há muitos valores nulos para as variáveis do tipo inteiro, sendo que apenas a variável LotFrontage apresenta cerca de 17.74 % de valores ausentes, mais adiante iremos decidir se está variável permanece ou será retirada de nosso conjunto de dados.

Obs.: Pode ser que seja possível através da média, mediana, knn e outra técnica imputar valores na variável LotFrontage, afim de preencher seus valores nulos.

5.2 Tipo Categorical: % de valores nulos

missing <- apply(is.na(df.cat),2,function(x){ 
                                    nulos <-100*sum(as.numeric(x))/length(x)
                                    round(nulos,2)
                                    }) %>% 
           sort(decreasing = T)
missing
##        PoolQC   MiscFeature         Alley         Fence   FireplaceQu 
##         99.52         96.30         93.77         80.75         47.26 
##    GarageType  GarageFinish    GarageQual    GarageCond  BsmtExposure 
##          5.55          5.55          5.55          5.55          2.60 
##  BsmtFinType2      BsmtQual      BsmtCond  BsmtFinType1    MasVnrType 
##          2.60          2.53          2.53          2.53          0.55 
##    Electrical      MSZoning        Street      LotShape   LandContour 
##          0.07          0.00          0.00          0.00          0.00 
##     Utilities     LotConfig     LandSlope  Neighborhood    Condition1 
##          0.00          0.00          0.00          0.00          0.00 
##    Condition2      BldgType    HouseStyle     RoofStyle      RoofMatl 
##          0.00          0.00          0.00          0.00          0.00 
##   Exterior1st   Exterior2nd     ExterQual     ExterCond    Foundation 
##          0.00          0.00          0.00          0.00          0.00 
##       Heating     HeatingQC    CentralAir   KitchenQual    Functional 
##          0.00          0.00          0.00          0.00          0.00 
##    PavedDrive      SaleType SaleCondition 
##          0.00          0.00          0.00

Veja que as variáveis PoolQC, MiscFeature, Alley, Fence e FireplaceQu não nos deixam outra alternativa senão a remoção delas do conjunto de dados, pois neste caso, a imputação de dados seria um grande problema na propagação do erro considerando as incertezas associadas aos métodos de imputação.

6 Selecionando Variáveis

Dos resultados acima iremos retirar de nosso conjunto de dados algumas variáveis.

6.1 Selecão de Variável tipo inteiro:

  • LotFrontage (retiramos por questões de tempo)
df.int <- df.int %>% 
            select(-LotFrontage)
df.int

6.2 Selecão de Variável Tipo Sring:

  • PoolQC
  • MiscFeature
  • Alley
  • Fence
  • FireplaceQu
df.cat <- df.cat %>% 
            select(-PoolQC,-MiscFeature,
                   -Alley,-Fence,-FireplaceQu)
df.cat

7 Juntandos os data frames

Jutando os dados tipo inteiros e string.

df.train <- bind_cols(df.int,df.cat)
df.train

8 Removendo valores nulos das linhas

Nosso df.train possui 1460 linhas. Se removermos os valores nulos das linhas será que ainda teremos volume de dados significativo ? Ou seja, qual a porcentagem de valores nulos nas linhas ?

paste(round(100*(1-(nrow(na.omit(df.train))/nrow(df.train))),2),"%")
## [1] "8.36 %"

Com 8.36 % ainda nos sobre mais de 90% dos dados para análise, dessa forma removeremos os valores nulos das linhas.

df.train <- na.omit(df.train)
df.train

Agora com 1338 linhas nosso df.train encontra-se limpo e pronto para ser explorado.

9 Dados de teste

Iremos realizar nos dados de teste as mesmas transformações aplicadas aos dados de treino.

df.test <- data.table::fread('../dados/test.csv', 
                             sep=",", 
                             showProgress = FALSE)  %>% 
            data.frame(stringsAsFactors = F)
df.test

10 Selecionando as variáveis

Removendo as mesmas variáveis do conjunto de treinamento.

df.test <- df.test %>%
              select(-LotFrontage,-PoolQC,
                     -MiscFeature,-Alley,
                     -Fence,-FireplaceQu)

11 Separando o conjunto de dados de teste pelo tipo.

tipo <- lapply(df.test,class)

11.1 Dados tipo inteiro

test.int <- df.test[,unlist(tipo) %in% "integer"]
test.int

11.2 Dados tipo string

test.str <- df.test[,unlist(tipo) %in% "character"]
test.str

11.3 Tranformando dados tipo string em categorical.

test.cat <- lapply(test.str,factor) %>% data.frame()
test.cat

12 Juntandos os data frames

Jutando os dados tipo inteiros e string.

df.test <- bind_cols(test.int,test.cat)
df.test

13 Removendo valores nulos das linhas

Nosso df.train possui 1459 linhas. Se removermos os valores nulos das linhas será que ainda teremos volume de dados significativo ? Ou seja, qual a porcentagem de valores nulos nas linhas ?

paste(round(100*(1-(nrow(na.omit(df.test))/nrow(df.test))),2),"%")
## [1] "9.6 %"

Com 9.6 % ainda nos sobre mais de 90% dos dados para análise, dessa forma removeremos os valores nulos das linhas.

df.test <- na.omit(df.test)
df.test

Agora com 1319 linhas nosso df.test encontra-se limpo e pronto para ser explorado.

14 Exportando os dados limpos

write.csv(df.train,'../outputs/df.train.csv')
write.csv(df.test,'../outputs/df.test.csv')

Sérgio Carvalho

20 março, 2019